/*
 *      network.cpp
 *      
 *      Copyright 2009 AzureSky <AzureSky.fedora@gmail.com>
 *      
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */


#include "network.h"

net_opt::net_opt()
{
}

net_opt::~net_opt()
{
}

/* enable/disable Selective Acknowledgment*/
int net_opt::about_ipv4_tcp_sack()
{
	int tcp_sack[] = {CTL_NET,NET_IPV4,NET_IPV4_TCP_SACK};
	int curr;
	size_t curr_size = sizeof(curr);
	
	int result = sysctl(tcp_sack,3,&curr,&curr_size,0,0);
	
	return (result != -1 ? curr : result);
}

int net_opt::change_ipv4_tcp_sack(int arg)
{
	int tcp_sack[] = {CTL_NET,NET_IPV4,NET_IPV4_TCP_SACK};
	int new_value = arg;
	size_t new_size = sizeof(new_value);
	
	int result = sysctl(tcp_sack,3,0,0,&new_value,new_size);
	if(result == -1){
		return -1;
	}
	
	return about_ipv4_tcp_sack();
}

/* enable/disable Forward Acknowledgment*/
int net_opt::about_ipv4_tcp_fack()
{
	int tcp_fack[] = {CTL_NET,NET_IPV4,NET_TCP_FACK};
	int curr;
	size_t curr_size = sizeof(curr);
	
	int result = sysctl(tcp_fack,3,&curr,&curr_size,0,0);
	
	return (result != -1 ? curr : result);
}

int net_opt::change_ipv4_tcp_fack(int arg)
{
	int tcp_fack[] = {CTL_NET,NET_IPV4,NET_TCP_FACK};
	int new_value = arg;
	size_t new_size = sizeof(new_value);
	
	int result = sysctl(tcp_fack,3,0,0,&new_value,new_size);
	if(result == -1){
		return -1;
	}
	
	return about_ipv4_tcp_fack();
}

/* enable/disable ip forward*/
int net_opt::about_ipv4_ip_forward()
{
	int ip_forward[] = {CTL_NET,NET_IPV4,NET_IPV4_FORWARD};
	int curr;
	size_t curr_size = sizeof(curr);
	
	int result = sysctl(ip_forward,3,&curr,&curr_size,0,0);
	
	return (result != -1 ? curr : result);
}

int net_opt::change_ipv4_ip_forward(int arg)
{
	int ip_forward[] = {CTL_NET,NET_IPV4,NET_IPV4_FORWARD};
	int new_value = arg;
	size_t new_size = sizeof(new_value);
	
	int result = sysctl(ip_forward,3,0,0,&new_value,new_size);
	if(result == -1){
		return -1;
	}
	
	return about_ipv4_ip_forward();
}

/* enable/disable tcp timestamps*/
int net_opt::about_ipv4_tcp_timestamps()
{
	int time_stamps[] = {CTL_NET,NET_IPV4,NET_IPV4_TCP_TIMESTAMPS};
	int curr;
	size_t curr_size = sizeof(curr);
	
	int result = sysctl(time_stamps,3,&curr,&curr_size,0,0);
	
	return (result != -1 ? curr : result);
}

int net_opt::change_ipv4_tcp_timestamps(int arg)
{
	int time_stamps[] = {CTL_NET,NET_IPV4,NET_IPV4_TCP_TIMESTAMPS};
	int new_value = arg;
	size_t new_size = sizeof(new_value);
	
	int result = sysctl(time_stamps,3,0,0,&new_value,new_size);
	if(result == -1){
		return -1;
	}
	
	return about_ipv4_tcp_timestamps();
}

/* enable/disable RFC 1323  window scaling*/
int net_opt::about_ipv4_tcp_win_scaling()
{
	int win_scaling[] = {CTL_NET,NET_IPV4,NET_IPV4_TCP_WINDOW_SCALING};
	int curr;
	size_t curr_size = sizeof(curr);
	
	int result = sysctl(win_scaling,3,&curr,&curr_size,0,0);
	
	return (result != -1 ? curr : result);
}

int net_opt::change_ipv4_tcp_win_scaling(int arg)
{
	int win_scaling[] = {CTL_NET,NET_IPV4,NET_IPV4_TCP_WINDOW_SCALING};
	int new_value = arg;
	size_t new_size = sizeof(new_value);
	
	int result = sysctl(win_scaling,3,0,0,&new_value,new_size);
	if(result == -1){
		return -1;
	}
	
	return about_ipv4_tcp_win_scaling();
}

/* enable/disable tcp low_latency*/
int net_opt::about_ipv4_tcp_low_latency()
{
	int low_latency[] = {CTL_NET,NET_IPV4,NET_TCP_LOW_LATENCY};
	int curr;
	size_t curr_size = sizeof(curr);
	
	int result = sysctl(low_latency,3,&curr,&curr_size,0,0);
	
	return (result != -1 ? curr : result);
}

int net_opt::change_ipv4_tcp_low_latency(int arg)
{
	int low_latency[] = {CTL_NET,NET_IPV4,NET_TCP_LOW_LATENCY};
	int new_value = arg;
	size_t new_size = sizeof(new_value);
	
	int result = sysctl(low_latency,3,0,0,&new_value,new_size);
	if(result == -1){
		return -1;
	}
	
	return about_ipv4_tcp_low_latency();
}

/* set the default rmen size*/
long net_opt::about_core_rmem_default()
{
	int rmem_default[] = {CTL_NET,NET_CORE,NET_CORE_RMEM_DEFAULT};
	long curr;
	size_t curr_size = sizeof(curr);
	
	int result = sysctl(rmem_default,3,&curr,&curr_size,0,0);
	
	return (result != -1 ? curr : result);
}

long net_opt::change_core_rmem_default(long arg)
{
	int rmem_default[] = {CTL_NET,NET_CORE,NET_CORE_RMEM_DEFAULT};
	long new_value = arg;
	size_t new_size = sizeof(new_value);
	
	int result = sysctl(rmem_default,3,0,0,&new_value,new_size);
	if(result == -1){
		return -1;
	}
	
	return about_core_rmem_default();
}

/* set the max rmem size*/
long net_opt::about_core_rmem_max()
{
	int rmem_max[] = {CTL_NET,NET_CORE,NET_CORE_RMEM_MAX};
	long curr;
	size_t curr_size = sizeof(curr);
	
	int result = sysctl(rmem_max,3,&curr,&curr_size,0,0);
	
	return (result != -1 ? curr : result);
}

long net_opt::change_core_rmem_max(long arg)
{
	int rmem_max[] = {CTL_NET,NET_CORE,NET_CORE_RMEM_MAX};
	long new_value = arg;
	size_t new_size = sizeof(new_value);
	
	int result = sysctl(rmem_max,3,0,0,&new_value,new_size);
	if(result == -1){
		return -1;
	}
	
	return about_core_rmem_max();
}

/* set the default wmen size*/
long net_opt::about_core_wmem_default()
{
	int wmem_default[] = {CTL_NET,NET_CORE,NET_CORE_WMEM_DEFAULT};
	long curr;
	size_t curr_size = sizeof(curr);
	
	int result = sysctl(wmem_default,3,&curr,&curr_size,0,0);
	
	return (result != -1 ? curr : result);
}

long net_opt::change_core_wmem_default(long arg)
{
	int wmem_default[] = {CTL_NET,NET_CORE,NET_CORE_WMEM_DEFAULT};
	long new_value = arg;
	size_t new_size = sizeof(new_value);
	
	int result = sysctl(wmem_default,3,0,0,&new_value,new_size);
	if(result == -1){
		return -1;
	}
	
	return about_core_wmem_default();
}

/* set the max wmem size*/
long net_opt::about_core_wmem_max()
{
	int wmem_max[] = {CTL_NET,NET_CORE,NET_CORE_WMEM_MAX};
	long curr;
	size_t curr_size = sizeof(curr);
	
	int result = sysctl(wmem_max,3,&curr,&curr_size,0,0);
	
	return (result != -1 ? curr : result);
}

long net_opt::change_core_wmem_max(long arg)
{
	int wmem_max[] = {CTL_NET,NET_CORE,NET_CORE_WMEM_MAX};
	long new_value = arg;
	size_t new_size = sizeof(new_value);
	
	int result = sysctl(wmem_max,3,0,0,&new_value,new_size);
	if(result == -1){
		return -1;
	}
	
	return about_core_wmem_max();
}

/* set the tcp mem size*/
tcp_mem net_opt::about_tcp_mem()
{
	int tcpmem[] = {CTL_NET,NET_IPV4,NET_TCP_MEM};
	long curr[3];
	tcp_mem curr_mem;
	size_t curr_size = sizeof(curr);
	
	int result = sysctl(tcpmem,3,&curr,&curr_size,0,0);
	
	if(result != -1){
		curr_mem.min_mem = curr[0];
		curr_mem.default_mem = curr[1];
		curr_mem.max_mem = curr[2];
	}else{
		curr_mem.min_mem = -1;
		curr_mem.default_mem = -1;
		curr_mem.max_mem = -1;
	}
	
	return curr_mem;
}

tcp_mem net_opt::change_tcp_mem(tcp_mem arg)
{
	int tcpmem[] = {CTL_NET,NET_IPV4,NET_TCP_MEM};
	long new_value[3];
	new_value[0] = arg.min_mem;
	new_value[1] = arg.default_mem;
	new_value[2] = arg.max_mem;
	size_t new_size = sizeof(new_value);
	
	int result = sysctl(tcpmem,3,0,0,&new_value,new_size);
	
	if (result == -1){
		arg.min_mem = -1;
		arg.default_mem = -1;
		arg.max_mem = -1;
		return arg;
	}
	
	return about_tcp_mem();
}

/* set the tcp wmem size*/
tcp_mem net_opt::about_tcp_wmem()
{
	int tcp_wmem[] = {CTL_NET,NET_IPV4,NET_TCP_WMEM};
	long curr[3];
	tcp_mem curr_wmem;
	size_t curr_size = sizeof(curr);
	
	int result = sysctl(tcp_wmem,3,&curr,&curr_size,0,0);
	
	if(result != -1){
		curr_wmem.min_mem = curr[0];
		curr_wmem.default_mem = curr[1];
		curr_wmem.max_mem = curr[2];
	}else{
		curr_wmem.min_mem = -1;
		curr_wmem.default_mem = -1;
		curr_wmem.max_mem = -1;
	}
	
	return curr_wmem;
}

tcp_mem net_opt::change_tcp_wmem(tcp_mem arg)
{
	int tcp_wmem[] = {CTL_NET,NET_IPV4,NET_TCP_WMEM};
	long new_value[3];
	new_value[0] = arg.min_mem;
	new_value[1] = arg.default_mem;
	new_value[2] = arg.max_mem;
	size_t new_size = sizeof(new_value);
	
	int result = sysctl(tcp_wmem,3,0,0,&new_value,new_size);
	
	if (result == -1){
		arg.min_mem = -1;
		arg.default_mem = -1;
		arg.max_mem = -1;
		return arg;
	}
	
	return about_tcp_wmem();
}

/* set the tcp rmem size*/
tcp_mem net_opt::about_tcp_rmem()
{
	int tcp_rmem[] = {CTL_NET,NET_IPV4,NET_TCP_RMEM};
	long curr[3];
	tcp_mem curr_rmem;
	size_t curr_size = sizeof(curr);
	
	int result = sysctl(tcp_rmem,3,&curr,&curr_size,0,0);
	
	if(result != -1){
		curr_rmem.min_mem = curr[0];
		curr_rmem.default_mem = curr[1];
		curr_rmem.max_mem = curr[2];
	}else{
		curr_rmem.min_mem = -1;
		curr_rmem.default_mem = -1;
		curr_rmem.max_mem = -1;
	}
	
	return curr_rmem;
}

tcp_mem net_opt::change_tcp_rmem(tcp_mem arg)
{
	int tcp_rmem[] = {CTL_NET,NET_IPV4,NET_TCP_RMEM};
	long new_value[3];
	new_value[0] = arg.min_mem;
	new_value[1] = arg.default_mem;
	new_value[2] = arg.max_mem;
	size_t new_size = sizeof(new_value);
	
	int result = sysctl(tcp_rmem,3,0,0,&new_value,new_size);
	
	if (result == -1){
		arg.min_mem = -1;
		arg.default_mem = -1;
		arg.max_mem = -1;
		return arg;
	}
	
	return about_tcp_rmem();
}
